home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume15 / rmtlib < prev    next >
Encoding:
Internet Message Format  |  1988-05-30  |  22.2 KB

  1. Subject:  v15i021:  Remote magtape library for BSD
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: "Arnold D. Robbins" <emoryu1!arnold>
  6. Posting-number: Volume 15, Issue 21
  7. Archive-name: rmtlib
  8.  
  9. Here is the latest version of the Remote Mag Tape library. There have been
  10. some bug fixes since the last posting, and the 4.2 syntax is now available
  11. only as a compile-time option.
  12.  
  13. This package provides a simple means of transparently accessing tape drives
  14. on remote machines over the ethernet, via rsh and rmt.
  15.  
  16. These routines are used like their corresponding system calls, but allow
  17. the user to open up a tape drive on a remote system on which he or she has
  18. an account and the appropriate remote permissions.
  19.  
  20.  
  21. Arnold
  22. ---------------------------------------------
  23. #! /bin/sh
  24. # This is a shell archive, meaning:
  25. # 1. Remove everything above the #! /bin/sh line.
  26. # 2. Save the resulting text in a file.
  27. # 3. Execute the file with /bin/sh (not csh) to create the files:
  28. #    rmtops.3
  29. #    rmt.h
  30. #    rmtlib.c
  31. #    Makefile
  32. # This archive created: Fri Oct 30 10:38:51 1987
  33. export PATH; PATH=/bin:$PATH
  34. echo shar: extracting "'rmtops.3'" '(4639 characters)'
  35. if test -f 'rmtops.3'
  36. then
  37.     echo shar: will not over-write existing file "'rmtops.3'"
  38. else
  39. cat << \SHAR_EOF > 'rmtops.3'
  40. ...
  41. ... $Header: rmtops.3,v 1.3 87/10/30 10:36:38 root Locked $
  42. ... 
  43. ... $Log:    rmtops.3,v $
  44. ... Revision 1.3  87/10/30  10:36:38  root
  45. ... Some cleanup. 4.3 syntax is default, 4.2 is a compile time option.
  46. ... 
  47. ... Revision 1.2  86/10/09  16:38:02  root
  48. ... Changed to reflect 4.3BSD rcp syntax and better rmt(8) capabilities. ADR.
  49. ... 
  50. ... Revision 1.1  86/10/09  16:18:47  root
  51. ... Initial revision
  52. ... 
  53. ...
  54. .TH RMTOPS 3 local
  55. .SH NAME
  56. rmtops \- access tape drives on remote machines
  57. .SH SYNOPSIS
  58. .nf
  59. .ft B
  60. #include <rmt.h>
  61. #include <sys/stat.h>    /* MUST come after <rmt.h> */
  62.  
  63. int isrmt (fd)
  64. int fd;
  65.  
  66. int rmtaccess (file, mode)
  67. char *file;
  68. int mode;
  69.  
  70. int rmtclose (fd)
  71. int fd;
  72.  
  73. int rmtcreat (file, mode)
  74. char *file;
  75. int mode;
  76.  
  77. int rmtdup (fd)
  78. int fd;
  79.  
  80. int rmtfcntl (fd, cmd, arg)
  81. int fd, cmd, arg;
  82.  
  83. int rmtfstat (fd, buf)
  84. int fd;
  85. struct stat *buf;
  86.  
  87. int rmtioctl (fd, request, argp)
  88. int fd, request;
  89. char *argp;
  90.  
  91. int rmtisatty (fd)
  92. int fd;
  93.  
  94. long rmtlseek (fd, offset, whence)
  95. int fd, whence;
  96. long offset;
  97.  
  98. int rmtlstat (file, buf)
  99. char *file;
  100. struct stat *buf;
  101.  
  102. int rmtopen (file, flags [, mode])
  103. char *file;
  104. int flags, mode;
  105.  
  106. int rmtread (fd, buf, nbytes)
  107. int fd, nbytes;
  108. char *buf;
  109.  
  110. int rmtstat (file, buf)
  111. char *file;
  112. struct stat *buf;
  113.  
  114. int rmtwrite (fd, buf, nbytes)
  115. int fd, nbytes;
  116. char *buf;
  117. .fi
  118. .ft R
  119. .SH DESCRIPTION
  120. .I Rmtops
  121. provides a simple means of transparently accessing tape drives
  122. on remote machines over the ethernet, via
  123. .IR rsh (1)
  124. and
  125. .IR rmt (8).
  126. These routines are used like their corresponding
  127. system calls, but allow the user to open up a tape drive on a remote
  128. system on which he or she has an account and the appropriate remote
  129. permissions.
  130. .PP
  131. A remote tape drive file name has the form
  132. .sp
  133. .RS
  134. .RI [ user @] system :/dev/???
  135. .RE
  136. .sp
  137. where
  138. .I system
  139. is the remote system,
  140. .I /dev/???
  141. is the particular drive on the remote system (raw, blocked, rewinding,
  142. non-rewinding, etc.), and the optional
  143. .I user
  144. is the login name to be used on the remote system, if different from
  145. the current user's login name.
  146. .PP
  147. The library source code may be optionally compiled to recognize the
  148. old, 4.2 BSD, remote syntax
  149. .sp
  150. .RS
  151. .IR system [. user ]:/dev/???
  152. .RE
  153. .sp
  154. By default, only the first form (introduced in 4.3 BSD) is recognized.
  155. .PP
  156. For transparency, the user should include the file
  157. .IR <rmt.h> ,
  158. which has the following defines in it:
  159. .PP
  160. .nf
  161. #define access rmtaccess
  162. #define close rmtclose
  163. #define creat rmtcreat
  164. #define dup rmtdup
  165. #define fcntl rmtfcntl
  166. #define fstat rmtfstat
  167. #define ioctl rmtioctl
  168. #define isatty rmtisatty
  169. #define lseek rmtlseek
  170. #define lstat rmtlstat
  171. #define open rmtopen
  172. #define read rmtread
  173. #define stat rmtstat
  174. #define write rmtwrite
  175. .fi
  176. .PP
  177. This allows the programmer to use
  178. .IR open ,
  179. .IR close ,
  180. .IR read ,
  181. .IR write ,
  182. etc. in their normal fashion, with the
  183. .I rmtops
  184. routines taking care of differentiating between local and remote files.
  185. This file should be included
  186. .I before
  187. including the file
  188. .IR <sys/stat.h> ,
  189. since it redefines the identifier ``stat,'' which is used to declare
  190. objects of type
  191. .BR "struct stat" .
  192. .PP
  193. The routines differentiate between local and remote file descriptors by
  194. adding a bias (currently 128) to the file descriptor of the pipe.
  195. The programmer, if he or she must know if a file is remote, should use the
  196. .I isrmt
  197. function.
  198. .SH FILES
  199. .TP
  200. .B /usr/lib/librmt.a
  201. Contains the remote tape library.  To include the library with a program,
  202. add the flag
  203. .B \-lrmt
  204. to the
  205. .IR cc (1)
  206. command line.
  207. .SH SEE ALSO
  208. .IR rcp (1),
  209. .IR rsh (1),
  210. .IR rmt (8),
  211. and the appropriate system calls in section 2.
  212. .SH DIAGNOSTICS
  213. Several of these routines will return \-1 and set
  214. .I errno
  215. to EOPNOTSUPP, if they are given a remote file name or a file descriptor
  216. on an open remote file (e.g.,
  217. .IR rmtdup ).
  218. .SH BUGS
  219. See \s-1DIAGNOSTICS\s+1 above.  It is to be hoped that true remote file systems
  220. will eventually appear, and eliminate the need for these routines.
  221. .PP
  222. There is no way to use remote tape drives with the
  223. .IR stdio (3)
  224. package, short of recompiling it entirely to use these routines.
  225. .PP
  226. The
  227. .IR rmt (8)
  228. protocol is not very capable.  In particular, it relies on
  229. TCP/IP sockets for error free transmission, and does no data validation
  230. of its own.
  231. .SH AUTHORS
  232. Jeff Lee (gatech!jeff) wrote the original routines for accessing
  233. tape drives via
  234. .IR rmt (8).
  235. .PP
  236. Fred Fish (unisoft!fnf) redid them into a general purpose library.
  237. .PP
  238. Arnold Robbins
  239. (formerly gatech!arnold, now emory!arnold)
  240. added the ability to specify a user
  241. name on the remote system, the
  242. .B <rmt.h>
  243. include file, this man page,
  244. cleaned up the library a little,
  245. and made the appropriate changes for 4.3 BSD.
  246. SHAR_EOF
  247. fi # end of overwriting check
  248. echo shar: extracting "'rmt.h'" '(1056 characters)'
  249. if test -f 'rmt.h'
  250. then
  251.     echo shar: will not over-write existing file "'rmt.h'"
  252. else
  253. cat << \SHAR_EOF > 'rmt.h'
  254. /*
  255.  * $Header: rmt.h,v 1.1 86/10/09 16:17:20 root Locked $
  256.  *
  257.  * $Log:    rmt.h,v $
  258.  * Revision 1.1  86/10/09  16:17:20  root
  259.  * Initial revision
  260.  * 
  261.  */
  262.  
  263. /*
  264.  *    rmt.h
  265.  *
  266.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  267.  *    The preprocessor can be used to remap these the rmtopen(), etc
  268.  *    thus minimizing source changes.
  269.  *
  270.  *    This file must be included before <sys/stat.h>, since it redefines
  271.  *    stat to be rmtstat, so that struct stat xyzzy; declarations work
  272.  *    properly.
  273.  *
  274.  *    -- Fred Fish (w/some changes by Arnold Robbins)
  275.  */
  276.  
  277.  
  278. #ifndef access        /* avoid multiple redefinition */
  279. #ifndef lint        /* in this case what lint doesn't know won't hurt it */
  280. #define access rmtaccess
  281. #define close rmtclose
  282. #define creat rmtcreat
  283. #define dup rmtdup
  284. #define fcntl rmtfcntl
  285. #define fstat rmtfstat
  286. #define ioctl rmtioctl
  287. #define isatty rmtisatty
  288. #define lseek rmtlseek
  289. #define lstat rmtlstat
  290. #define open rmtopen
  291. #define read rmtread
  292. #define stat rmtstat
  293. #define write rmtwrite
  294.  
  295. extern long rmtlseek ();    /* all the rest are int's */
  296. #endif
  297. #endif
  298. SHAR_EOF
  299. fi # end of overwriting check
  300. echo shar: extracting "'rmtlib.c'" '(14658 characters)'
  301. if test -f 'rmtlib.c'
  302. then
  303.     echo shar: will not over-write existing file "'rmtlib.c'"
  304. else
  305. cat << \SHAR_EOF > 'rmtlib.c'
  306. #ifndef lint
  307. static char *RCSid = "$Header: rmtlib.c,v 1.4 87/10/30 10:36:12 root Locked $";
  308. #endif
  309.  
  310. /*
  311.  * $Log:    rmtlib.c,v $
  312.  * Revision 1.4  87/10/30  10:36:12  root
  313.  * Made 4.2 syntax a compile time option. ADR.
  314.  * 
  315.  * Revision 1.3  87/04/22  11:16:48  root
  316.  * Two fixes from parmelee@wayback.cs.cornell.edu to correctly
  317.  * do fd biasing and rmt protocol on 'S' command. ADR.
  318.  * 
  319.  * Revision 1.2  86/10/09  16:38:53  root
  320.  * Changed to reflect 4.3BSD rcp syntax. ADR.
  321.  * 
  322.  * Revision 1.1  86/10/09  16:17:35  root
  323.  * Initial revision
  324.  * 
  325.  */
  326.  
  327. /*
  328.  *    rmt --- remote tape emulator subroutines
  329.  *
  330.  *    Originally written by Jeff Lee, modified some by Arnold Robbins
  331.  *
  332.  *    WARNING:  The man page rmt(8) for /etc/rmt documents the remote mag
  333.  *    tape protocol which rdump and rrestore use.  Unfortunately, the man
  334.  *    page is *WRONG*.  The author of the routines I'm including originally
  335.  *    wrote his code just based on the man page, and it didn't work, so he
  336.  *    went to the rdump source to figure out why.  The only thing he had to
  337.  *    change was to check for the 'F' return code in addition to the 'E',
  338.  *    and to separate the various arguments with \n instead of a space.  I
  339.  *    personally don't think that this is much of a problem, but I wanted to
  340.  *    point it out.
  341.  *    -- Arnold Robbins
  342.  *
  343.  *    Redone as a library that can replace open, read, write, etc, by
  344.  *    Fred Fish, with some additional work by Arnold Robbins.
  345.  */
  346.  
  347. /*
  348.  *    MAXUNIT --- Maximum number of remote tape file units
  349.  *
  350.  *    READ --- Return the number of the read side file descriptor
  351.  *    WRITE --- Return the number of the write side file descriptor
  352.  */
  353.  
  354. #define RMTIOCTL    1
  355.  
  356. #include <stdio.h>
  357. #include <signal.h>
  358. #include <sys/types.h>
  359.  
  360. #ifdef RMTIOCTL
  361. #include <sys/ioctl.h>
  362. #include <sys/mtio.h>
  363. #endif
  364.  
  365. #include <errno.h>
  366. #include <setjmp.h>
  367. #include <sys/stat.h>
  368.  
  369. #define BUFMAGIC    64    /* a magic number for buffer sizes */
  370. #define MAXUNIT    4
  371.  
  372. #define READ(fd)    (Ctp[fd][0])
  373. #define WRITE(fd)    (Ptc[fd][1])
  374.  
  375. static int Ctp[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  376. static int Ptc[MAXUNIT][2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  377.  
  378. static jmp_buf Jmpbuf;
  379. extern int errno;
  380.  
  381. /*
  382.  *    abort --- close off a remote tape connection
  383.  */
  384.  
  385. static void abort(fildes)
  386. int fildes;
  387. {
  388.     close(READ(fildes));
  389.     close(WRITE(fildes));
  390.     READ(fildes) = -1;
  391.     WRITE(fildes) = -1;
  392. }
  393.  
  394.  
  395.  
  396. /*
  397.  *    command --- attempt to perform a remote tape command
  398.  */
  399.  
  400. static int command(fildes, buf)
  401. int fildes;
  402. char *buf;
  403. {
  404.     register int blen;
  405.     int (*pstat)();
  406.  
  407. /*
  408.  *    save current pipe status and try to make the request
  409.  */
  410.  
  411.     blen = strlen(buf);
  412.     pstat = signal(SIGPIPE, SIG_IGN);
  413.     if (write(WRITE(fildes), buf, blen) == blen)
  414.     {
  415.         signal(SIGPIPE, pstat);
  416.         return(0);
  417.     }
  418.  
  419. /*
  420.  *    something went wrong. close down and go home
  421.  */
  422.  
  423.     signal(SIGPIPE, pstat);
  424.     abort(fildes);
  425.  
  426.     errno = EIO;
  427.     return(-1);
  428. }
  429.  
  430.  
  431.  
  432. /*
  433.  *    status --- retrieve the status from the pipe
  434.  */
  435.  
  436. static int status(fildes)
  437. int fildes;
  438. {
  439.     int i;
  440.     char c, *cp;
  441.     char buffer[BUFMAGIC];
  442.  
  443. /*
  444.  *    read the reply command line
  445.  */
  446.  
  447.     for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++)
  448.     {
  449.         if (read(READ(fildes), cp, 1) != 1)
  450.         {
  451.             abort(fildes);
  452.             errno = EIO;
  453.             return(-1);
  454.         }
  455.         if (*cp == '\n')
  456.         {
  457.             *cp = 0;
  458.             break;
  459.         }
  460.     }
  461.  
  462.     if (i == BUFMAGIC)
  463.     {
  464.         abort(fildes);
  465.         errno = EIO;
  466.         return(-1);
  467.     }
  468.  
  469. /*
  470.  *    check the return status
  471.  */
  472.  
  473.     for (cp = buffer; *cp; cp++)
  474.         if (*cp != ' ')
  475.             break;
  476.  
  477.     if (*cp == 'E' || *cp == 'F')
  478.     {
  479.         errno = atoi(cp + 1);
  480.         while (read(READ(fildes), &c, 1) == 1)
  481.             if (c == '\n')
  482.                 break;
  483.  
  484.         if (*cp == 'F')
  485.             abort(fildes);
  486.  
  487.         return(-1);
  488.     }
  489.  
  490. /*
  491.  *    check for mis-synced pipes
  492.  */
  493.  
  494.     if (*cp != 'A')
  495.     {
  496.         abort(fildes);
  497.         errno = EIO;
  498.         return(-1);
  499.     }
  500.  
  501.     return(atoi(cp + 1));
  502. }
  503.  
  504.  
  505.  
  506. /*
  507.  *    _rmt_open --- open a magtape device on system specified, as given user
  508.  *
  509.  *    file name has the form [user@]system:/dev/????
  510. #ifdef COMPAT
  511.  *    file name has the form system[.user]:/dev/????
  512. #endif
  513.  */
  514.  
  515. #define MAXHOSTLEN    257    /* BSD allows very long host names... */
  516.  
  517. static int _rmt_open (path, oflag, mode)
  518. char *path;
  519. int oflag;
  520. int mode;
  521. {
  522.     int i, rc;
  523.     char buffer[BUFMAGIC];
  524.     char system[MAXHOSTLEN];
  525.     char device[BUFMAGIC];
  526.     char login[BUFMAGIC];
  527.     char *sys, *dev, *user;
  528.  
  529.     sys = system;
  530.     dev = device;
  531.     user = login;
  532.  
  533. /*
  534.  *    first, find an open pair of file descriptors
  535.  */
  536.  
  537.     for (i = 0; i < MAXUNIT; i++)
  538.         if (READ(i) == -1 && WRITE(i) == -1)
  539.             break;
  540.  
  541.     if (i == MAXUNIT)
  542.     {
  543.         errno = EMFILE;
  544.         return(-1);
  545.     }
  546.  
  547. /*
  548.  *    pull apart system and device, and optional user
  549.  *    don't munge original string
  550.  *    if COMPAT is defined, also handle old (4.2) style person.site notation.
  551.  */
  552.  
  553.     while (*path != '@'
  554. #ifdef COMPAT
  555.             && *path != '.'
  556. #endif
  557.             && *path != ':') {
  558.         *sys++ = *path++;
  559.     }
  560.     *sys = '\0';
  561.     path++;
  562.  
  563.     if (*(path - 1) == '@')
  564.     {
  565.         (void) strcpy (user, sys);    /* saw user part of user@host */
  566.         sys = system;            /* start over */
  567.         while (*path != ':') {
  568.             *sys++ = *path++;
  569.         }
  570.         *sys = '\0';
  571.         path++;
  572.     }
  573. #ifdef COMPAT
  574.     else if (*(path - 1) == '.')
  575.     {
  576.         while (*path != ':') {
  577.             *user++ = *path++;
  578.         }
  579.         *user = '\0';
  580.         path++;
  581.     }
  582. #endif
  583.     else
  584.         *user = '\0';
  585.  
  586.     while (*path) {
  587.         *dev++ = *path++;
  588.     }
  589.     *dev = '\0';
  590.  
  591. /*
  592.  *    setup the pipes for the 'rsh' command and fork
  593.  */
  594.  
  595.     if (pipe(Ptc[i]) == -1 || pipe(Ctp[i]) == -1)
  596.         return(-1);
  597.  
  598.     if ((rc = fork()) == -1)
  599.         return(-1);
  600.  
  601.     if (rc == 0)
  602.     {
  603.         close(0);
  604.         dup(Ptc[i][0]);
  605.         close(Ptc[i][0]); close(Ptc[i][1]);
  606.         close(1);
  607.         dup(Ctp[i][1]);
  608.         close(Ctp[i][0]); close(Ctp[i][1]);
  609.         (void) setuid (getuid ());
  610.         (void) setgid (getgid ());
  611.         if (*user)
  612.         {
  613.             execl("/usr/ucb/rsh", "rsh", system, "-l", login,
  614.                 "/etc/rmt", (char *) 0);
  615.             execl("/usr/bin/remsh", "remsh", system, "-l", login,
  616.                 "/etc/rmt", (char *) 0);
  617.         }
  618.         else
  619.         {
  620.             execl("/usr/ucb/rsh", "rsh", system,
  621.                 "/etc/rmt", (char *) 0);
  622.             execl("/usr/bin/remsh", "remsh", system,
  623.                 "/etc/rmt", (char *) 0);
  624.         }
  625.  
  626. /*
  627.  *    bad problems if we get here
  628.  */
  629.  
  630.         perror("exec");
  631.         exit(1);
  632.     }
  633.  
  634.     close(Ptc[i][0]); close(Ctp[i][1]);
  635.  
  636. /*
  637.  *    now attempt to open the tape device
  638.  */
  639.  
  640.     sprintf(buffer, "O%s\n%d\n", device, oflag);
  641.     if (command(i, buffer) == -1 || status(i) == -1)
  642.         return(-1);
  643.  
  644.     return(i);
  645. }
  646.  
  647.  
  648.  
  649. /*
  650.  *    _rmt_close --- close a remote magtape unit and shut down
  651.  */
  652.  
  653. static int _rmt_close(fildes)
  654. int fildes;
  655. {
  656.     int rc;
  657.  
  658.     if (command(fildes, "C\n") != -1)
  659.     {
  660.         rc = status(fildes);
  661.  
  662.         abort(fildes);
  663.         return(rc);
  664.     }
  665.  
  666.     return(-1);
  667. }
  668.  
  669.  
  670.  
  671. /*
  672.  *    _rmt_read --- read a buffer from a remote tape
  673.  */
  674.  
  675. static int _rmt_read(fildes, buf, nbyte)
  676. int fildes;
  677. char *buf;
  678. unsigned int nbyte;
  679. {
  680.     int rc, i;
  681.     char buffer[BUFMAGIC];
  682.  
  683.     sprintf(buffer, "R%d\n", nbyte);
  684.     if (command(fildes, buffer) == -1 || (rc = status(fildes)) == -1)
  685.         return(-1);
  686.  
  687.     for (i = 0; i < rc; i += nbyte, buf += nbyte)
  688.     {
  689.         nbyte = read(READ(fildes), buf, rc);
  690.         if (nbyte <= 0)
  691.         {
  692.             abort(fildes);
  693.             errno = EIO;
  694.             return(-1);
  695.         }
  696.     }
  697.  
  698.     return(rc);
  699. }
  700.  
  701.  
  702.  
  703. /*
  704.  *    _rmt_write --- write a buffer to the remote tape
  705.  */
  706.  
  707. static int _rmt_write(fildes, buf, nbyte)
  708. int fildes;
  709. char *buf;
  710. unsigned int nbyte;
  711. {
  712.     int rc;
  713.     char buffer[BUFMAGIC];
  714.     int (*pstat)();
  715.  
  716.     sprintf(buffer, "W%d\n", nbyte);
  717.     if (command(fildes, buffer) == -1)
  718.         return(-1);
  719.  
  720.     pstat = signal(SIGPIPE, SIG_IGN);
  721.     if (write(WRITE(fildes), buf, nbyte) == nbyte)
  722.     {
  723.         signal (SIGPIPE, pstat);
  724.         return(status(fildes));
  725.     }
  726.  
  727.     signal (SIGPIPE, pstat);
  728.     abort(fildes);
  729.     errno = EIO;
  730.     return(-1);
  731. }
  732.  
  733.  
  734.  
  735. /*
  736.  *    _rmt_lseek --- perform an imitation lseek operation remotely
  737.  */
  738.  
  739. static long _rmt_lseek(fildes, offset, whence)
  740. int fildes;
  741. long offset;
  742. int whence;
  743. {
  744.     char buffer[BUFMAGIC];
  745.  
  746.     sprintf(buffer, "L%d\n%d\n", offset, whence);
  747.     if (command(fildes, buffer) == -1)
  748.         return(-1);
  749.  
  750.     return(status(fildes));
  751. }
  752.  
  753.  
  754. /*
  755.  *    _rmt_ioctl --- perform raw tape operations remotely
  756.  */
  757.  
  758. #ifdef RMTIOCTL
  759. static _rmt_ioctl(fildes, op, arg)
  760. int fildes, op;
  761. char *arg;
  762. {
  763.     char c;
  764.     int rc, cnt;
  765.     char buffer[BUFMAGIC];
  766.  
  767. /*
  768.  *    MTIOCOP is the easy one. nothing is transfered in binary
  769.  */
  770.  
  771.     if (op == MTIOCTOP)
  772.     {
  773.         sprintf(buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  774.             ((struct mtop *) arg)->mt_count);
  775.         if (command(fildes, buffer) == -1)
  776.             return(-1);
  777.         return(status(fildes));
  778.     }
  779.  
  780. /*
  781.  *    we can only handle 2 ops, if not the other one, punt
  782.  */
  783.  
  784.     if (op != MTIOCGET)
  785.     {
  786.         errno = EINVAL;
  787.         return(-1);
  788.     }
  789.  
  790. /*
  791.  *    grab the status and read it directly into the structure
  792.  *    this assumes that the status buffer is (hopefully) not
  793.  *    padded and that 2 shorts fit in a long without any word
  794.  *    alignment problems, ie - the whole struct is contiguous
  795.  *    NOTE - this is probably NOT a good assumption.
  796.  */
  797.  
  798.     if (command(fildes, "S") == -1 || (rc = status(fildes)) == -1)
  799.         return(-1);
  800.  
  801.     for (; rc > 0; rc -= cnt, arg += cnt)
  802.     {
  803.         cnt = read(READ(fildes), arg, rc);
  804.         if (cnt <= 0)
  805.         {
  806.             abort(fildes);
  807.             errno = EIO;
  808.             return(-1);
  809.         }
  810.     }
  811.  
  812. /*
  813.  *    now we check for byte position. mt_type is a small integer field
  814.  *    (normally) so we will check its magnitude. if it is larger than
  815.  *    256, we will assume that the bytes are swapped and go through
  816.  *    and reverse all the bytes
  817.  */
  818.  
  819.     if (((struct mtget *) arg)->mt_type < 256)
  820.         return(0);
  821.  
  822.     for (cnt = 0; cnt < rc; cnt += 2)
  823.     {
  824.         c = arg[cnt];
  825.         arg[cnt] = arg[cnt+1];
  826.         arg[cnt+1] = c;
  827.     }
  828.  
  829.     return(0);
  830.   }
  831. #endif /* RMTIOCTL */
  832.  
  833. /*
  834.  *    Added routines to replace open(), close(), lseek(), ioctl(), etc.
  835.  *    The preprocessor can be used to remap these the rmtopen(), etc
  836.  *    thus minimizing source changes:
  837.  *
  838.  *        #ifdef <something>
  839.  *        #  define access rmtaccess
  840.  *        #  define close rmtclose
  841.  *        #  define creat rmtcreat
  842.  *        #  define dup rmtdup
  843.  *        #  define fcntl rmtfcntl
  844.  *        #  define fstat rmtfstat
  845.  *        #  define ioctl rmtioctl
  846.  *        #  define isatty rmtisatty
  847.  *        #  define lseek rmtlseek
  848.  *        #  define lstat rmtlstat
  849.  *        #  define open rmtopen
  850.  *        #  define read rmtread
  851.  *        #  define stat rmtstat
  852.  *        #  define write rmtwrite
  853.  *        #  define access rmtaccess
  854.  *        #  define close rmtclose
  855.  *        #  define creat rmtcreat
  856.  *        #  define dup rmtdup
  857.  *        #  define fcntl rmtfcntl
  858.  *        #  define fstat rmtfstat
  859.  *        #  define ioctl rmtioctl
  860.  *        #  define lseek rmtlseek
  861.  *        #  define open rmtopen
  862.  *        #  define read rmtread
  863.  *        #  define stat rmtstat
  864.  *        #  define write rmtwrite
  865.  *        #endif
  866.  *
  867.  *    -- Fred Fish
  868.  *
  869.  *    ADR --- I set up a <rmt.h> include file for this
  870.  *
  871.  */
  872.  
  873. /*
  874.  *    Note that local vs remote file descriptors are distinquished
  875.  *    by adding a bias to the remote descriptors.  This is a quick
  876.  *    and dirty trick that may not be portable to some systems.
  877.  */
  878.  
  879. #define REM_BIAS 128
  880.  
  881.  
  882. /*
  883.  *    Test pathname to see if it is local or remote.  A remote device
  884.  *    is any string that contains ":/dev/".  Returns 1 if remote,
  885.  *    0 otherwise.
  886.  */
  887.  
  888. static int remdev (path)
  889. register char *path;
  890. {
  891. #define strchr    index
  892.     extern char *strchr ();
  893.  
  894.     if ((path = strchr (path, ':')) != NULL)
  895.     {
  896.         if (strncmp (path + 1, "/dev/", 5) == 0)
  897.         {
  898.             return (1);
  899.         }
  900.     }
  901.     return (0);
  902. }
  903.  
  904.  
  905. /*
  906.  *    Open a local or remote file.  Looks just like open(2) to
  907.  *    caller.
  908.  */
  909.  
  910. int rmtopen (path, oflag, mode)
  911. char *path;
  912. int oflag;
  913. int mode;
  914. {
  915.     if (remdev (path))
  916.     {
  917.         return (_rmt_open (path, oflag, mode) + REM_BIAS);
  918.     }
  919.     else
  920.     {
  921.         return (open (path, oflag, mode));
  922.     }
  923. }
  924.  
  925. /*
  926.  *    Test pathname for specified access.  Looks just like access(2)
  927.  *    to caller.
  928.  */
  929.  
  930. int rmtaccess (path, amode)
  931. char *path;
  932. int amode;
  933. {
  934.     if (remdev (path))
  935.     {
  936.         return (0);        /* Let /etc/rmt find out */
  937.     }
  938.     else
  939.     {
  940.         return (access (path, amode));
  941.     }
  942. }
  943.  
  944.  
  945. /*
  946.  *    Read from stream.  Looks just like read(2) to caller.
  947.  */
  948.   
  949. int rmtread (fildes, buf, nbyte)
  950. int fildes;
  951. char *buf;
  952. unsigned int nbyte;
  953. {
  954.     if (isrmt (fildes))
  955.     {
  956.         return (_rmt_read (fildes - REM_BIAS, buf, nbyte));
  957.     }
  958.     else
  959.     {
  960.         return (read (fildes, buf, nbyte));
  961.     }
  962. }
  963.  
  964.  
  965. /*
  966.  *    Write to stream.  Looks just like write(2) to caller.
  967.  */
  968.  
  969. int rmtwrite (fildes, buf, nbyte)
  970. int fildes;
  971. char *buf;
  972. unsigned int nbyte;
  973. {
  974.     if (isrmt (fildes))
  975.     {
  976.         return (_rmt_write (fildes - REM_BIAS, buf, nbyte));
  977.     }
  978.     else
  979.     {
  980.         return (write (fildes, buf, nbyte));
  981.     }
  982. }
  983.  
  984. /*
  985.  *    Perform lseek on file.  Looks just like lseek(2) to caller.
  986.  */
  987.  
  988. long rmtlseek (fildes, offset, whence)
  989. int fildes;
  990. long offset;
  991. int whence;
  992. {
  993.     if (isrmt (fildes))
  994.     {
  995.         return (_rmt_lseek (fildes - REM_BIAS, offset, whence));
  996.     }
  997.     else
  998.     {
  999.         return (lseek (fildes, offset, whence));
  1000.     }
  1001. }
  1002.  
  1003.  
  1004. /*
  1005.  *    Close a file.  Looks just like close(2) to caller.
  1006.  */
  1007.  
  1008. int rmtclose (fildes)
  1009. int fildes;
  1010. {
  1011.     if (isrmt (fildes))
  1012.     {
  1013.         return (_rmt_close (fildes - REM_BIAS));
  1014.     }
  1015.     else
  1016.     {
  1017.         return (close (fildes));
  1018.     }
  1019. }
  1020.  
  1021. /*
  1022.  *    Do ioctl on file.  Looks just like ioctl(2) to caller.
  1023.  */
  1024.  
  1025. int rmtioctl (fildes, request, arg)
  1026. int fildes, request, arg;
  1027. {
  1028.     if (isrmt (fildes))
  1029.     {
  1030. #ifdef RMTIOCTL
  1031.         return (_rmt_ioctl (fildes - REM_BIAS, request, arg));
  1032. #else
  1033.         errno = EOPNOTSUPP;
  1034.         return (-1);        /* For now  (fnf) */
  1035. #endif
  1036.     }
  1037.     else
  1038.     {
  1039.         return (ioctl (fildes, request, arg));
  1040.     }
  1041. }
  1042.  
  1043.  
  1044. /*
  1045.  *    Duplicate an open file descriptor.  Looks just like dup(2)
  1046.  *    to caller.
  1047.  */
  1048.  
  1049. int rmtdup (fildes)
  1050. int fildes;
  1051. {
  1052.     if (isrmt (fildes))
  1053.     {
  1054.         errno = EOPNOTSUPP;
  1055.         return (-1);        /* For now (fnf) */
  1056.     }
  1057.     else
  1058.     {
  1059.         return (dup (fildes));
  1060.     }
  1061. }
  1062.  
  1063. /*
  1064.  *    Get file status.  Looks just like fstat(2) to caller.
  1065.  */
  1066.  
  1067. int rmtfstat (fildes, buf)
  1068. int fildes;
  1069. struct stat *buf;
  1070. {
  1071.     if (isrmt (fildes))
  1072.     {
  1073.         errno = EOPNOTSUPP;
  1074.         return (-1);        /* For now (fnf) */
  1075.     }
  1076.     else
  1077.     {
  1078.         return (fstat (fildes, buf));
  1079.     }
  1080. }
  1081.  
  1082.  
  1083. /*
  1084.  *    Get file status.  Looks just like stat(2) to caller.
  1085.  */
  1086.  
  1087. int rmtstat (path, buf)
  1088. char *path;
  1089. struct stat *buf;
  1090. {
  1091.     if (remdev (path))
  1092.     {
  1093.         errno = EOPNOTSUPP;
  1094.         return (-1);        /* For now (fnf) */
  1095.     }
  1096.     else
  1097.     {
  1098.         return (stat (path, buf));
  1099.     }
  1100. }
  1101.  
  1102.  
  1103.  
  1104. /*
  1105.  *    Create a file from scratch.  Looks just like creat(2) to the caller.
  1106.  */
  1107.  
  1108. #include <sys/file.h>        /* BSD DEPENDANT!!! */
  1109. /* #include <fcntl.h>        /* use this one for S5 with remote stuff */
  1110.  
  1111. int rmtcreat (path, mode)
  1112. char *path;
  1113. int mode;
  1114. {
  1115.     if (remdev (path))
  1116.     {
  1117.         return (rmtopen (path, 1 | O_CREAT, mode));
  1118.     }
  1119.     else
  1120.     {
  1121.         return (creat (path, mode));
  1122.     }
  1123. }
  1124.  
  1125. /*
  1126.  *    Isrmt. Let a programmer know he has a remote device.
  1127.  */
  1128.  
  1129. int isrmt (fd)
  1130. int fd;
  1131. {
  1132.     return (fd >= REM_BIAS);
  1133. }
  1134.  
  1135. /*
  1136.  *    Rmtfcntl. Do a remote fcntl operation.
  1137.  */
  1138.  
  1139. int rmtfcntl (fd, cmd, arg)
  1140. int fd, cmd, arg;
  1141. {
  1142.     if (isrmt (fd))
  1143.     {
  1144.         errno = EOPNOTSUPP;
  1145.         return (-1);
  1146.     }
  1147.     else
  1148.     {
  1149.         return (fcntl (fd, cmd, arg));
  1150.     }
  1151. }
  1152.  
  1153. /*
  1154.  *    Rmtisatty.  Do the isatty function.
  1155.  */
  1156.  
  1157. int rmtisatty (fd)
  1158. int fd;
  1159. {
  1160.     if (isrmt (fd))
  1161.         return (0);
  1162.     else
  1163.         return (isatty (fd));
  1164. }
  1165.  
  1166.  
  1167. /*
  1168.  *    Get file status, even if symlink.  Looks just like lstat(2) to caller.
  1169.  */
  1170.  
  1171. int rmtlstat (path, buf)
  1172. char *path;
  1173. struct stat *buf;
  1174. {
  1175.     if (remdev (path))
  1176.     {
  1177.         errno = EOPNOTSUPP;
  1178.         return (-1);        /* For now (fnf) */
  1179.     }
  1180.     else
  1181.     {
  1182.         return (lstat (path, buf));
  1183.     }
  1184. }
  1185. SHAR_EOF
  1186. fi # end of overwriting check
  1187. echo shar: extracting "'Makefile'" '(421 characters)'
  1188. if test -f 'Makefile'
  1189. then
  1190.     echo shar: will not over-write existing file "'Makefile'"
  1191. else
  1192. cat << \SHAR_EOF > 'Makefile'
  1193. #
  1194. # $Header: Makefile,v 1.1 86/10/09 16:42:13 root Locked $
  1195. #
  1196. # $Log:    Makefile,v $
  1197. # Revision 1.1  86/10/09  16:42:13  root
  1198. # Initial revision
  1199. #
  1200. # Makefile for rmtlib
  1201.  
  1202. CFLAGS= -O
  1203. SRC= rmtlib.c
  1204. DOC= rmtops.3
  1205.  
  1206. MANSEC=3
  1207. DEST= /usr/lib
  1208.  
  1209. librmt.a: rmtlib.o
  1210.     ar rv librmt.a rmtlib.o
  1211.  
  1212. install: librmt.a
  1213.     cp librmt.a /usr/lib
  1214.     ranlib /usr/lib/librmt.a
  1215.     cp $(DOC) /usr/man/man$(MANSEC)/rmtops.$(MANSEC)
  1216.  
  1217. clean:
  1218.     rm -f rmtlib.o
  1219. SHAR_EOF
  1220. fi # end of overwriting check
  1221. #    End of shell archive
  1222. exit 0
  1223.  
  1224.